#ifndef USBRELAYBOARDX440_H
#define USBRELAYBOARDX440_H

#include <QObject>

class QextSerialPort;


/**
 * Structure d'change de donnes pour le MVC
 * @note la structure est suffisemment petite pour se permettre
 * de la passer par copie
 */
typedef struct _stUSBRelayBoardX440
{
    struct
    {
        bool relay1 : 1;
        bool relay2 : 1;
        bool relay3 : 1;
        bool relay4 : 1;
        bool input1 : 1;
        bool input2 : 1;
        bool input3 : 1;
        bool input4 : 1;
    }readStatus;

    struct
    {
        bool relay1 : 1;
        bool relay2 : 1;
        bool relay3 : 1;
        bool relay4 : 1;
        bool input1 : 1;
        bool input2 : 1;
        bool input3 : 1;
        bool input4 : 1;
    }requestedStatus;

    struct
    {
        unsigned int input1;
        unsigned int input2;
        unsigned int input3;
        unsigned int input4;
    }readValue;
}stUSBRelayBoardX440;



//-------------------------------------------------------------------------------- USBRelayBoardX440Model
class USBRelayBoardX440Model : public QObject
{
    Q_OBJECT

    public:
        // todo : Ajouter constructeur par copie et affectation ou utiliser Q_DISABLE_COPY(USBRelayBoardX440)
        explicit USBRelayBoardX440Model(QObject *parent = 0);

        enum entryMode { analog, digital };
        enum relayState { open, closed };

        // Individual relay control
        bool openRelay(unsigned int relayNumber);
        bool closeRelay(unsigned int relayNumber);
        bool setRelayState(unsigned int relayNumber, USBRelayBoardX440Model::relayState state);

        // Global relay control
        bool openAllRelays(void);
        bool closeAllRelays(void);

        // Global reading of the relays'states
        QString readRelaysStates(void);

        // Individual reading of a relay'state
        bool readRelayState(unsigned int numeroRelais);



        // Individual input control
        bool setInputMode(unsigned int inputNumber, USBRelayBoardX440Model::entryMode mode);

        /// @todo return a reference or a pointer, not a copy
        QStringList getGetCOMPortList(void);

        bool deviceConnection(QString& COMPortName, bool disconnectPort);

    signals:
        //----- Signals to the controller (cannot be declared virtual)
        void signalInputLevelChanged(stUSBRelayBoardX440 status);
        void signalCOMConfigurationChanged(QString& COMPortName, bool connected);

    public slots:

    private:
        QextSerialPort *m_serialPort;

        char commandsStack[16];
        char* endStackAddress;
        char* stackOverflowAddress;
        char* pushCommandAddress;
        char* popCommandAddress;

    private slots:
        void onReadyRead();
        void onDsrChanged(bool status);
};


/**
 * Abstract class that a view must inherit from in order to talk to the controller.
 */
//-------------------------------------------------------------------------------- USBRelayBoardX440AbstractView
class USBRelayBoardX440AbstractView : public QObject
{
    Q_OBJECT

    public :
        explicit USBRelayBoardX440AbstractView(QObject *parent = 0) : QObject(parent) { }
        virtual ~USBRelayBoardX440AbstractView() { }

    public slots :
        //----- Actions that emit inherited signals to the controller
        virtual void slotGetCOMConfiguration(void) = 0;
        virtual void slotSetCOMConfiguration(void) = 0;

    public :
        //----- Methods called by the controller to update the view
        virtual void updateCOMConfiguration(const QStringList& comPortStringList) = 0;
        virtual void updateView(stUSBRelayBoardX440 status) = 0;


    //----- Signals to the controller (cannot be declared virtual)
    signals :
        void signalGetCOMConfiguration(void);
        void signalSetCOMConfiguration(QString& selectedCOMPort, bool disconnect = false);
        void signalViewChanged(stUSBRelayBoardX440 status);
};


//-------------------------------------------------------------------------------- USBRelayBoardX440Controller
class USBRelayBoardX440Controller : public QObject
{
    Q_OBJECT

    public :
        explicit USBRelayBoardX440Controller(QObject *parent = 0);
        virtual ~USBRelayBoardX440Controller() { setView(0); delete m_view; setModel(0); delete m_model; }

        //----- Getters and setters for the view and the model
        void setView(USBRelayBoardX440AbstractView *view = 0);
        USBRelayBoardX440AbstractView* getView() const { return m_view; }
        void setModel(USBRelayBoardX440Model *model = 0);
        USBRelayBoardX440Model* getModel() const { return m_model; }

    private :
        USBRelayBoardX440Model *m_model;
        USBRelayBoardX440AbstractView *m_view;

        void initialize(void);

    public slots :
        //----- Intercept signals coming from the view
        void slotGetCOMConfiguration(void);
        void slotSetCOMConfiguration(QString& selectedCOMPort, bool disconnectPort = false);
        void slotViewChanged(stUSBRelayBoardX440 status);

        //----- Intercept signals coming from the model
        void slotInputLevelChanged(stUSBRelayBoardX440 status);
        void slotCOMConfigurationChanged(QString& COMPortName, bool connected);
};

#endif // USBRELAYBOARDX440_H
